package com.xyz.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.xyz.dao.mapper.RepairDaoMapper;
import com.xyz.dao.pojo.FaultTypeVo;
import com.xyz.dto.CountDto;
import com.xyz.dto.HomeLocalDateDto;
import com.xyz.dto.enums.EnumRepState;
import com.xyz.entity.mapper.*;
import com.xyz.entity.pojo.*;
import com.xyz.service.CommonService;
import com.xyz.service.HomeMaintenService;
import com.xyz.util.dto.DataResult;
import com.xyz.util.dto.LoginInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.DecimalFormat;
import java.time.*;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
@Transactional(rollbackFor = Exception.class)
public class HomeMaintenServiceImpl implements HomeMaintenService {


    @Autowired
    private RepairWorkOrderMapper repairWorkOrderMapper;

    @Autowired
    private UpkeepWorkOrderMapper upkeepWorkOrderMapper;

    @Autowired
    private SystemDictTypeMapper systemDictTypeMapper;

    @Autowired
    private SystemDictDataMapper systemDictDataMapper;

    @Autowired
    private CommonService commonService;

    @Autowired
    private RepairDaoMapper repairDao;

    /*
    * 维修看板-头部信息
    * */
    @Override
    public DataResult selectHeadRo(LoginInfo loginInfo, CountDto countDto) throws Exception {
        Map<String, Object> resultMap = new HashMap<>();
        //获取当天0点时间
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date dayTime = calendar.getTime();
        HomeLocalDateDto getDto = commonService.selectCountTime(countDto);
        //当天的工单
        RepairWorkOrderExample example2 = new RepairWorkOrderExample();
        RepairWorkOrderExample.Criteria repairCriteria2 = example2.createCriteria();
        repairCriteria2.andCreateTimeGreaterThanOrEqualTo(dayTime);
        List<RepairWorkOrder> todayRepairWorkOrderList = repairWorkOrderMapper.selectByExample(example2);
        //维修工单总览
        Map<String, Object> repairMap = getRepairMap(getDto, todayRepairWorkOrderList);
        //维保工单总览
        Map<String, Object> upkeepMap = getUpkeepMap(getDto, dayTime);
        //今日异常
        Map<String, Object> todayErrMap = getTodayErrMap(todayRepairWorkOrderList, dayTime);
        //本周异常
        Map<String, Object> weekErrMap = getWeekErrMap();
        resultMap.put("repair", repairMap);
        resultMap.put("upkeep", upkeepMap);
        resultMap.put("todayErr", todayErrMap);
        resultMap.put("weekErr", weekErrMap);
        return DataResult.build9100(resultMap);
    }

    /*
    * 维修看板-故障曲线图
    * */
    @Override
    public DataResult selectFault(LoginInfo loginInfo, CountDto countDto) throws Exception {
        Map<String, Object> resultMap = new HashMap<>();
        HomeLocalDateDto getDto = commonService.selectCountTime(countDto);
        //开始日期
        LocalDate firstDay = getDto.getFirstDay();
        //结束日期
        LocalDate lastDay = getDto.getLastDay();

        List<LocalDate> LocalDateList = getDateListBetweenDates(firstDay,lastDay);
        //日期排序
        List<String> dateNameList = LocalDateList.stream().map(t -> t.getMonth().getValue() + "-" + t.getDayOfMonth()).collect(Collectors.toList());
        resultMap.put("dateNameList",dateNameList);
        //获取故障数据
        List<FaultTypeVo> voList = repairDao.queryFaultTypeByTime(firstDay, lastDay.atTime(LocalTime.MAX));
        List<Map<String, Object>> rows = new ArrayList<>();
        //故障类别List
        List<SystemDictData> sddList = commonService.getSysDateListByCode("TYPE_REP_MAINTENANCE");
        //数据分组
        Map<Integer, List<FaultTypeVo>> voListMap = new HashMap<>();
        if(CollUtil.isNotEmpty(voList)){
            voListMap = voList.stream().collect(Collectors.groupingBy(FaultTypeVo :: getMtcFaultType));
        }
        for (SystemDictData dictData:sddList){
            List<FaultTypeVo> faultTypeVos = voListMap.get(dictData.getDictValue());
            Map<String, Object> rowMap = new HashMap<>();
            List<Integer> rowCountList = new ArrayList<>();
            //故障名称
            rowMap.put("name",dictData.getDictName());
            for(LocalDate localDate:LocalDateList){
                boolean fag = true;
                if(CollUtil.isNotEmpty(faultTypeVos)){
                    for(FaultTypeVo faultTypeVo:faultTypeVos){
                        if(localDate.equals(faultTypeVo.getDay())){
                            rowCountList.add(faultTypeVo.getCount());
                            fag = false;
                            faultTypeVos.remove(faultTypeVo);
                            break;
                        }
                    }
                }
                if(fag){
                    rowCountList.add(0);
                }
            }
            rowMap.put("list",rowCountList);
            rows.add(rowMap);
        }
        resultMap.put("rows",rows);
        return DataResult.build9100(resultMap);
    }

    /*
    * 人员工单排行
    * */
    @Override
    public DataResult selectRoPersonRanking(LoginInfo loginInfo, CountDto countDto) throws Exception{
        Map<String, Object> resultMap = new HashMap<>();
        HomeLocalDateDto getDto = commonService.selectCountTime(countDto);
        Integer pageSize = null;
        if(StrUtil.isNotBlank(countDto.getPageSize())){
            pageSize = Integer.parseInt(countDto.getPageSize());
        }
        //查询工单数
        List<Map<String, Object>> roPersonRankingList = repairDao.queryRoPersonRanking(getDto.getStartTime(), getDto.getEndTime(), pageSize);
        //查询工时数量
        List<Map<String, Object>> hoursPersonRankingList = repairDao.queryHoursPersonRanking(getDto.getStartTime(), getDto.getEndTime(), pageSize);

        resultMap.put("roList",roPersonRankingList);
        resultMap.put("hoursList",hoursPersonRankingList);
        return DataResult.build9100(resultMap);
    }

    /*
    * 人员评分排行
    * */
    @Override
    public DataResult selectScorePersonRanking(LoginInfo loginInfo, CountDto countDto) throws Exception{
        Map<String, Object> resultMap = new HashMap<>();
        HomeLocalDateDto getDto = commonService.selectCountTime(countDto);
        Integer pageSize = null;
        if(StrUtil.isNotBlank(countDto.getPageSize())){
            pageSize = Integer.parseInt(countDto.getPageSize());
        }
        //查询人员评分排行
        List<Map<String, Object>> scoreList = repairDao.queryScorePersonList(getDto.getStartTime(), getDto.getEndTime(), pageSize);
        resultMap.put("scoreList",scoreList);
        return DataResult.build9100(resultMap);
    }

    /*
    * 设备故障类型分布饼状图
    * */
    @Override
    public DataResult selectFaultPie(LoginInfo loginInfo, CountDto countDto) throws Exception{
        Map<String, Object> resultMap = new HashMap<>();
        HomeLocalDateDto getDto = commonService.selectCountTime(countDto);
        //查询设备故障类型数
        List<FaultTypeVo> faultTypeVoList = repairDao.queryFaultPieList(getDto.getStartTime(), getDto.getEndTime());
        List<SystemDictData> sddList = commonService.getSysDateListByCode("TYPE_REP_MAINTENANCE");
        List<Map<String, Object>> FaultPieList = new ArrayList<>();
        for(SystemDictData dictData:sddList){
            Map<String, Object> rowMap = new HashMap<>();
            //故障名称
            rowMap.put("name",dictData.getDictName());
            int count = 0;
            for(FaultTypeVo vo:faultTypeVoList){
                if(dictData.getDictValue().equals(vo.getMtcFaultType())){
                    count = vo.getCount();
                    break;
                }
            }
            //数量
            rowMap.put("count", count);
            FaultPieList.add(rowMap);
        }

        resultMap.put("FaultPieList",FaultPieList);
        return DataResult.build9100(resultMap);
    }

    /*
    * 设备故障原因分析
    * */
    @Override
    public DataResult selectReason(LoginInfo loginInfo, CountDto countDto) throws Exception {
        Map<String, Object> resultMap = new HashMap<>();
        HomeLocalDateDto getDto = commonService.selectCountTime(countDto);
        Integer pageSize = null;
        if(StrUtil.isNotBlank(countDto.getPageSize())){
            pageSize = Integer.parseInt(countDto.getPageSize());
        }
        //查询设备故障原因
        List<Map<String, Object>> reasonList = repairDao.queryReasonList(getDto.getStartTime(), getDto.getEndTime(), pageSize);
        Map<Integer, String> emTypeMap = commonService.getDictMap("TYPE_REP_REASON");

        for (Map<String, Object> map : reasonList) {
            Integer mtcFaultReason = MapUtil.getInt(map, "mtcFaultReason");
            if(mtcFaultReason != null){
                String mtcFaultReasonName = emTypeMap.get(mtcFaultReason);
                map.put("mtcFaultReasonName",mtcFaultReasonName);
            }
        }
        resultMap.put("reasonList",reasonList);
        return DataResult.build9100(resultMap);
    }

    /*
     * 维修来源分析
     * */
    @Override
    public DataResult selectRepairSource(LoginInfo loginInfo, CountDto countDto) throws Exception {
        Map<String, Object> resultMap = new HashMap<>();
        HomeLocalDateDto getDto = commonService.selectCountTime(countDto);
        //查询工单数量
        List<Map<String, Object>> repairSourceList = repairDao.queryRepairSourceList(getDto.getStartTime(), getDto.getEndTime());
        long sum = 0l;
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> repairMap = new HashMap<>();
        repairMap.put("name","新增维修");
        repairMap.put("count",0);
        Map<String, Object> upkeepMap = new HashMap<>();
        upkeepMap.put("name","维保转维修");
        upkeepMap.put("count",0);
        Map<String, Object> patrolMap = new HashMap<>();
        patrolMap.put("name","巡检转维修");
        patrolMap.put("count",0);
        for (Map<String, Object> map : repairSourceList) {
            Object sourceType = map.get("sourceType");
            Long count = MapUtil.getLong(map, "count");
            if (sourceType == null) {
                repairMap.put("count",count);
            } else {
                int type = (int) sourceType;
                if(type == 1){
                    upkeepMap.put("count",count);
                }else if(type == 2){
                    patrolMap.put("count",count);
                }
            }
            sum += count;
        }
        list.add(repairMap);
        list.add(upkeepMap);
        list.add(patrolMap);
        resultMap.put("repairList",list);
        resultMap.put("countSum",sum);
        return DataResult.build9100(resultMap);
    }

    /*
    * 备件使用排行
    * */
    @Override
    public DataResult selectPartRanking(LoginInfo loginInfo, CountDto countDto) throws Exception {
        Map<String, Object> resultMap = new HashMap<>();
        HomeLocalDateDto getDto = commonService.selectCountTime(countDto);
        Integer pageSize = null;
        if(StrUtil.isNotBlank(countDto.getPageSize())){
            pageSize = Integer.parseInt(countDto.getPageSize());
        }
        //查询备件使用排行
        List<Map<String, Object>> partRankingList = repairDao.queryPartRankingList(getDto.getStartTime(), getDto.getEndTime(), pageSize);
        resultMap.put("partRankingList",partRankingList);
        return DataResult.build9100(resultMap);
    }

    /*
    * 设备维修排行
    * */
    @Override
    public DataResult selectEmRanking(LoginInfo loginInfo, CountDto countDto) throws Exception {
        Map<String, Object> resultMap = new HashMap<>();
        HomeLocalDateDto getDto = commonService.selectCountTime(countDto);
        Integer pageSize = null;
        if(StrUtil.isNotBlank(countDto.getPageSize())){
            pageSize = Integer.parseInt(countDto.getPageSize());
        }
        //查询工单数
        List<Map<String, Object>> roEmRankingList = repairDao.queryRoEmRankingList(getDto.getStartTime(), getDto.getEndTime(), pageSize);
        //查询工时数量
        List<Map<String, Object>> hoursEmRankingList = repairDao.queryHoursEmRankingList(getDto.getStartTime(), getDto.getEndTime(), pageSize);

        resultMap.put("roEmList",roEmRankingList);
        resultMap.put("hoursEmList",hoursEmRankingList);
        return DataResult.build9100(resultMap);
    }

    //本周异常
    private Map<String, Object> getWeekErrMap() {
        Map<String, Object> weekErrMap = new HashMap<>();
        LocalDate now = LocalDate.now();
        //获取本周数据
        List<RepairWorkOrder> weekRepairWorkOrderList = getWeekRepairWorkOrderList(now);
        weekErrMap.put("total",weekRepairWorkOrderList.size());
        LocalDate lastWeekDate = now.minusWeeks(1);
        //获取上周数据
        List<RepairWorkOrder> lastWeekRepairWorkOrderList = getWeekRepairWorkOrderList(lastWeekDate);
        //较昨日
        weekErrMap.put("compareLast", weekRepairWorkOrderList.size() - lastWeekRepairWorkOrderList.size());
        dateErrMap(weekErrMap,weekRepairWorkOrderList);
        return weekErrMap;
    }

    private List<RepairWorkOrder> getWeekRepairWorkOrderList(LocalDate localDate){
        LocalTime timeStart = LocalTime.of(0, 0,0);
        LocalTime timeEnd = LocalTime.MAX;
        // 获取本周第一天
        LocalDate firstDayOfWeek = localDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDateTime firstDayDateTime = firstDayOfWeek.atTime(timeStart);
        Date firstDayDate = Date.from(firstDayDateTime.atZone(ZoneId.systemDefault()).toInstant());
        // 获取本周最后一天
        LocalDate lastDayOfWeek = localDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        LocalDateTime lastDayDateTime = lastDayOfWeek.atTime(timeEnd);
        Date lastDayDate = Date.from(lastDayDateTime.atZone(ZoneId.systemDefault()).toInstant());
        //查询本周的数据
        RepairWorkOrderExample example = new RepairWorkOrderExample();
        RepairWorkOrderExample.Criteria repairCriteria = example.createCriteria();
        repairCriteria.andCreateTimeGreaterThanOrEqualTo(firstDayDate);
        repairCriteria.andCreateTimeLessThanOrEqualTo(lastDayDate);
        return repairWorkOrderMapper.selectByExample(example);
    }

    //今日异常
    private Map<String, Object> getTodayErrMap(List<RepairWorkOrder> todayRepairWorkOrderList, Date dayTime) {
        Map<String, Object> todayErrMap = new HashMap<>();
        //今日异常数
        todayErrMap.put("total",todayRepairWorkOrderList.size());
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date lastDayTime = calendar.getTime();
        //昨天的工单
        RepairWorkOrderExample example = new RepairWorkOrderExample();
        RepairWorkOrderExample.Criteria repairCriteria = example.createCriteria();
        repairCriteria.andCreateTimeGreaterThanOrEqualTo(lastDayTime);
        repairCriteria.andCreateTimeLessThan(dayTime);
        List<RepairWorkOrder> lastDayRepairWorkOrderList = repairWorkOrderMapper.selectByExample(example);
        //较昨日
        todayErrMap.put("compareLast", todayRepairWorkOrderList.size() - lastDayRepairWorkOrderList.size());
        dateErrMap(todayErrMap,todayRepairWorkOrderList);
        return todayErrMap;
    }

    private void dateErrMap(Map<String, Object> errMap, List<RepairWorkOrder> todayRepairWorkOrderList) {
        //待审核
        Long pendingAnnounceCount = todayRepairWorkOrderList.stream().filter(t -> t.getRepState().intValue() == EnumRepState.PENDING_ANNOUNCE.getRepState()).count();
        errMap.put("pendingAnnounceCount",pendingAnnounceCount);
        //待分配
        long pendingCount = todayRepairWorkOrderList.stream().filter(t -> t.getRepState().intValue() == EnumRepState.PENDING_RECEIVE.getRepState() || t.getRepState().intValue() == EnumRepState.PENDING_REFUSE.getRepState() || t.getRepState().intValue() == EnumRepState.PENDING_TRANSFER.getRepState()).count();
        errMap.put("pendingCount",pendingCount);
        //处理中
        long processCount = todayRepairWorkOrderList.stream().filter(t -> t.getRepState().intValue() == EnumRepState.ALLOCATED.getRepState() || t.getRepState().intValue() == EnumRepState.UNDE_REPAIR.getRepState() || t.getRepState().intValue() == EnumRepState.SUSPEND_REPAIR.getRepState() || t.getRepState().intValue() == EnumRepState.ACCEPTED_NO.getRepState() || t.getRepState().intValue() == EnumRepState.ACCEPTED_YES.getRepState()).count();
        errMap.put("processCount",processCount);
        //超时
        Long timeoutCount = todayRepairWorkOrderList.stream().filter(t -> t.getRepState().intValue() == EnumRepState.MAINTENANCE_YES.getRepState() && t.getIsTimeout() != null && t.getIsTimeout() == 2).count();
        errMap.put("timeoutCount",timeoutCount);
    }

    //维修工单总览获取数据
    private Map<String, Object> getRepairMap(HomeLocalDateDto dto, List<RepairWorkOrder> todayRepairWorkOrderList) {
        //维修工单总览
        Map<String, Object> repairMap = new HashMap<>();
        //维修工单总数
        RepairWorkOrderExample example = new RepairWorkOrderExample();
        RepairWorkOrderExample.Criteria repairCriteria = example.createCriteria();
        repairCriteria.andCreateTimeGreaterThanOrEqualTo(dto.getStartTime());
        repairCriteria.andCreateTimeLessThanOrEqualTo(dto.getEndTime());
        List<RepairWorkOrder> repairWorkOrders = repairWorkOrderMapper.selectByExample(example);
        //维修工单总数
        int roTotal = repairWorkOrders.size();
        repairMap.put("roTotal",roTotal);

        //维修今天新增
        repairMap.put("todayAddCount",todayRepairWorkOrderList.size());
        //维修处理中
        Long processCount = repairWorkOrders.stream().filter(t -> t.getRepState() >= 6 && t.getRepState() <= 10).count();
        repairMap.put("processCount",processCount);
        //维修已完成
        Long completedCount = repairWorkOrders.stream().filter(t -> t.getRepState().intValue() == EnumRepState.MAINTENANCE_YES.getRepState()).count();
        repairMap.put("completedCount",completedCount);
        if(roTotal != 0){
            //完成率
            DecimalFormat decimalFormat = new DecimalFormat("0.0%");
            double rateDou = (double) completedCount / roTotal;
            String completedRate = decimalFormat.format(rateDou);
            repairMap.put("completedRate",completedRate);
        }else {
            repairMap.put("completedRate", "100%");
        }
        //获取超时工单数量
        Long timeoutCount = repairWorkOrders.stream().filter(t -> t.getRepState().intValue() == EnumRepState.MAINTENANCE_YES.getRepState() && t.getIsTimeout() != null && t.getIsTimeout() == 2).count();
        //超时率
        if(completedCount != 0){
            //完成率
            DecimalFormat decimalFormat = new DecimalFormat("0.0%");
            double rateDou = (double) timeoutCount / completedCount;
            String timeoutRate = decimalFormat.format(rateDou);
            repairMap.put("timeoutRate",timeoutRate);
        }else {
            repairMap.put("timeoutRate", "0.0%");
        }
        return repairMap;
    }

    //维保工单总览获取数据
    private Map<String, Object> getUpkeepMap(HomeLocalDateDto dto, Date dayTime) {
        //维保工单总览`
        Map<String, Object> upkeepMap = new HashMap<>();
        UpkeepWorkOrderExample example = new UpkeepWorkOrderExample();
        UpkeepWorkOrderExample.Criteria criteria = example.createCriteria();
        criteria.andCreateTimeGreaterThanOrEqualTo(dto.getStartTime());
        criteria.andCreateTimeLessThanOrEqualTo(dto.getEndTime());
        List<UpkeepWorkOrder> upkeepWorkOrders = upkeepWorkOrderMapper.selectByExample(example);
        //维保工单总数
        int roTotal = upkeepWorkOrders.size();
        upkeepMap.put("roTotal",roTotal);
        //查询当天维保数据
        UpkeepWorkOrderExample example2 = new UpkeepWorkOrderExample();
        UpkeepWorkOrderExample.Criteria criteria2 = example2.createCriteria();
        criteria2.andCreateTimeGreaterThanOrEqualTo(dayTime);
        List<UpkeepWorkOrder> todayupkeepWorkOrderList = upkeepWorkOrderMapper.selectByExample(example2);
        //维保今天新增
        upkeepMap.put("todayAddCount",todayupkeepWorkOrderList.size());
        //维保处理中
        Long processCount = upkeepWorkOrders.stream().filter(t -> t.getUpkeepState() >= 6 && t.getUpkeepState() <= 10).count();
        upkeepMap.put("processCount",processCount);
        //维修已完成
        Long completedCount = upkeepWorkOrders.stream().filter(t -> t.getUpkeepState().intValue() == EnumRepState.MAINTENANCE_YES.getRepState()).count();
        upkeepMap.put("completedCount",completedCount);
        if(roTotal != 0){
            //完成率
            DecimalFormat decimalFormat = new DecimalFormat("0.0%");
            double rateDou = (double) completedCount / roTotal;
            String completedRate = decimalFormat.format(rateDou);
            upkeepMap.put("completedRate",completedRate);
        }else {
            upkeepMap.put("completedRate", "100%");
        }
        //获取超时工单数量
        Long timeoutCount = upkeepWorkOrders.stream().filter(t -> t.getUpkeepState().intValue() == EnumRepState.MAINTENANCE_YES.getRepState() && t.getIsTimeout() != null && t.getIsTimeout() == 2).count();
        //超时率
        if(completedCount != 0){
            //完成率
            DecimalFormat decimalFormat = new DecimalFormat("0.0%");
            double rateDou = (double) timeoutCount / completedCount;
            String timeoutRate = decimalFormat.format(rateDou);
            upkeepMap.put("timeoutRate",timeoutRate);
        }else {
            upkeepMap.put("timeoutRate", "0.0%");
        }
        return upkeepMap;
    }

    private List<LocalDate> getDateListBetweenDates(LocalDate startDate, LocalDate endDate) {
        List<LocalDate> dateList = new ArrayList<>();
        while (!startDate.isAfter(endDate)) {
            dateList.add(startDate);
            startDate = startDate.plusDays(1);
        }
        return dateList;
    }
}
